//
//  CLHomeViewTransition.m
//  shortrent
//
//  Created by Leo on 2018/5/18.
//  Copyright © 2018年 mayi. All rights reserved.
//

#import "CLHomeViewTransition.h"
#import "UIView+ScreenShot.h"


static const NSString *kCenterImageViewBeginFrames = @"CenterImageViewBeginFrames";
static const NSString *kCenterImageViews = @"CenterImageViews";

typedef NS_ENUM(NSInteger, CLClipImageType) {
    CLClipImageTypeUp = 1,  // 裁切上部分
    CLClipImageTypeDown,    // 裁切下部分
    CLClipImageTypeCenter,  // 裁切中间部分
    CLClipImageTypeNone
};

@interface CLHomeViewTransition()

@property (strong,nonatomic) NSMutableArray<UIImageView *> *imageviewReusePool; // imageView 缓存池

@end

@implementation CLHomeViewTransition

// 开始做过渡动画
- (CLBeginTransitionBlock)transitionFromViewController:(UIViewController *)fromViewController
                                      toViewController:(UIViewController *)toViewController
                                     selectedIndexPath:(NSIndexPath *)indexPath
                                        collectionView:(UICollectionView *)collectionView
                                            completion:(CLCloseTransitionBlock)completion {
   
    /*
     将屏幕截图裁切为上中下三部分做动画
     */
    // 获取到点击的Cell 上面的imageview
    UICollectionViewCell *tapCell = [collectionView cellForItemAtIndexPath:indexPath];
    UIImageView *tapImageView = [self getImageViewForCollectionCell:tapCell];
    
    // 将点击到的imageview 的 frame 转换为 相对于 window 的frame
    CGRect tapImageViewFrame = [tapImageView.superview convertRect:tapImageView.frame toView:nil];
    
    // 计算将要裁切window 截图的裁切点 注意：此处裁切点有两个分别在点击的cell 的 imageview 的顶部和底部 即imageview.top imageview.bottom
    CGFloat upClipY = tapImageViewFrame.origin.y;
    CGFloat downClipY = upClipY + tapImageViewFrame.size.height;
    
    // 裁切到的上部分imageview 做动画时候的frame (相对于window)
    CGRect upImageViewBeginFrame = CGRectMake(0, 0, SCREEN_WIDTH, upClipY);
    CGRect upImageViewEndFrame = CGRectMake(0, -upClipY, SCREEN_WIDTH, upClipY);
    
    // 裁切到的下部分imageview 做动画时候的frame (相对于window)
    CGRect downImageViewBeginFrame = CGRectMake(0, downClipY, SCREEN_WIDTH, SCREEN_HEIGHT - downClipY);
    CGRect downImageViewEndFrame = CGRectMake(0, SCREEN_HEIGHT, SCREEN_WIDTH, SCREEN_HEIGHT - downClipY);
    
    // 将当前窗口截图
    UIImage *windowImage = [fromViewController.view.window captureCurrentView];
    
    // 将window 截图按照裁切点进行裁切
    UIImage *upImage = [self clipImage:windowImage clipPointY:upClipY clipType:CLClipImageTypeUp];
    UIImage *downImage = [self clipImage:windowImage clipPointY:downClipY clipType:CLClipImageTypeDown];
    
    // 创建两个做动画的iamgeview 并且添加到fromviewController 的 window 上
    UIImageView *upImageView = [self dequeueReuseImageView];
    upImageView.frame = upImageViewBeginFrame;
    upImageView.image = upImage;
    [fromViewController.view.window addSubview:upImageView];
    
    UIImageView *downImageView = [self dequeueReuseImageView];
    downImageView.frame = downImageViewBeginFrame;
    downImageView.image = downImage;
    [fromViewController.view.window addSubview:downImageView];
    
    // 获取collectionview 所有可见的 cell 的imageview 以及开始做动画的 frame (相对于window) 并将imageview 添加到当前窗口上
    NSDictionary *centerImageViewDict = [self addCenterImageViewsFromCollectionView:collectionView toFromViewController:fromViewController];
    __block NSMutableArray *centerImageViews = [centerImageViewDict objectForKey:kCenterImageViews];
    NSMutableArray *centerImageViewBeginFrames = [centerImageViewDict objectForKey:kCenterImageViewBeginFrames];
    
    // 根据点击的cell 的frame 计算出临近可见 cell 的frame 的终点坐标 (相对于window)
    NSMutableArray *centerImageviewEndFrames = [self calculateCenterImageViewEndFramesWithBeginFrames:centerImageViewBeginFrames tapImageViewFrame:tapImageViewFrame];
    
    // 开始做动画
    [UIView animateWithDuration:0.35 delay:0.1 options:UIViewAnimationOptionCurveEaseOut animations:^{
        // 隐藏当前view
        fromViewController.view.hidden = YES;
        // 暂时隐藏状态栏
        fromViewController.navigationController.navigationBar.hidden = YES;
        // 顶部上移
        upImageView.frame = upImageViewEndFrame;
        // 底部下移
        downImageView.frame = downImageViewEndFrame;
        // 中间部分的图片 即collectionview 中可见的cell 部分
        for (NSInteger i = 0; i < centerImageViews.count; i++) {
            UIImageView *centerImageView = centerImageViews[i];
            NSValue *value = centerImageviewEndFrames[i];
            CGRect frame = [value CGRectValue];
            centerImageView.frame = frame;
        }
    } completion:^(BOOL finished) {
        // 显示当前窗口view
        fromViewController.view.hidden = NO;
        // 进入下一级页面
        [fromViewController.navigationController pushViewController:toViewController animated:NO];
        // 第二个页面 淡入上移动画调用block
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            if (completion) {
                completion();
            }
        });
        // 重置上面执行动画的imageview 的image 并把imageview 放在缓存池里面
        [self enqueueImageView:upImageView];
        [self enqueueImageView:downImageView];
        for (UIImageView *centerImageView in centerImageViews) {
            [self enqueueImageView:centerImageView];
        }
        // 释放中间部分imageview 数组
        centerImageViews = nil;
        
    }];
    return [self completeAnimationWithUpImage:upImage upImageViewBeginFrame:upImageViewBeginFrame upImageViewEndFrame:upImageViewEndFrame downImage:downImage downImageViewBeginFrame:downImageViewBeginFrame downImageViewEndFrame:downImageViewEndFrame centerImageViewBeginFrames:centerImageViewBeginFrames centerImageViewEndFrames:centerImageviewEndFrames visibleCells:collectionView.visibleCells fromViewController:fromViewController toController:toViewController];
}

// 开始执行关闭动画
- (CLBeginTransitionBlock)completeAnimationWithUpImage:(UIImage *)upImage upImageViewBeginFrame:(CGRect)upImageViewBeginFrame upImageViewEndFrame:(CGRect)upImageViewEndFrame downImage:(UIImage *)downImage downImageViewBeginFrame:(CGRect)downImageViewBeginFrame downImageViewEndFrame:(CGRect)downImageViewEndFrame centerImageViewBeginFrames:(NSArray *)centerImageViewBeginFrames centerImageViewEndFrames:(NSArray *)centerImageViewEndFrames visibleCells:(NSArray *)visibleCells fromViewController:(UIViewController *)fromViewController toController:(UIViewController *)toViewController {
    // 关闭动画block
    __weak typeof(self) weakSelf = self;
    __weak typeof(toViewController) weakToViewController = toViewController;
    CLBeginTransitionBlock completeBlcok = ^(UIViewController *viewController){
        __strong typeof(weakSelf) strongSelf = weakSelf;
        __strong typeof(weakToViewController) strongToViewController = weakToViewController;
        if (!strongSelf) {
            return ;
        }
        /*
         添加做动画需要的 上下两个imageView
         以及collectionview 可见cell 的 imageView
         到窗口.
        */
        
        // 上面图片
        UIImageView *upImageView = [strongSelf dequeueReuseImageView];
        upImageView.frame = upImageViewEndFrame;
        upImageView.image = upImage;
        [viewController.view.window addSubview:upImageView];
        
        // 下面图片
        UIImageView *downImageView = [strongSelf dequeueReuseImageView];
        downImageView.frame = downImageViewEndFrame;
        downImageView.image = downImage;
        [viewController.view.window addSubview:downImageView];
        
        // collectionview 可见的所有cell 的 imageView
        __block NSMutableArray *centerImageViews = [NSMutableArray array];
        for (NSInteger i = 0; i<visibleCells.count; i++) {
            UIImageView *centerImageView = [strongSelf dequeueReuseImageView];
            [centerImageViews addObject:centerImageView];
            NSValue *value = centerImageViewEndFrames[i];
            CGRect frame = [value CGRectValue];
            centerImageView.frame = frame;
            UICollectionViewCell *visibleCell = visibleCells[i];
            centerImageView.image = [strongSelf getImageViewForCollectionCell:visibleCell].image;
            [viewController.view.window addSubview:centerImageView];
        }
        // 开始做关闭动画了
        [UIView animateWithDuration:0.35 delay:0.1 options:UIViewAnimationOptionCurveEaseOut animations:^{
            // 上部图片下移
            upImageView.frame = upImageViewBeginFrame;
            // 下部图片上移
            downImageView.frame = downImageViewBeginFrame;
            // 中间部分图片
            for (NSInteger i = 0; i<centerImageViews.count; i++) {
                UIImageView *centerImageView = centerImageViews[i];
                NSValue *value = centerImageViewBeginFrames[i];
                CGRect frame = [value CGRectValue];
                centerImageView.frame = frame;
            }
        } completion:^(BOOL finished) {
            // 重置做动画的imageview 的image 并放回缓存池
            [strongSelf enqueueImageView:upImageView];
            [strongSelf enqueueImageView:downImageView];
            for (UIImageView *centerImageView in centerImageViews) {
                [strongSelf enqueueImageView:centerImageView];
            }
            // 返回上一级视图
            [strongToViewController.navigationController popViewControllerAnimated:NO];
            // 释放中间部分图片数组
            centerImageViews = nil;
            // 显示状态栏
            [fromViewController.navigationController setNavigationBarHidden:NO];
        }];
    };
    return completeBlcok;
}

// 处理 collectionView 每个可见 cell, 创建一个做动画的 ImageView 添加到窗口
- (NSDictionary *)addCenterImageViewsFromCollectionView:(UICollectionView *)collectionView
                                   toFromViewController:(UIViewController *)fromViewController {
    NSArray *cells = collectionView.visibleCells;
    NSMutableArray *centerImageViews = [NSMutableArray arrayWithCapacity:cells.count];
    NSMutableArray *centerImageViewBeginFrames = [NSMutableArray arrayWithCapacity:cells.count];
    for (UICollectionViewCell *cell in cells) {
        
        // 先添加可见 cell 个数的动画 imageView 到窗口
        // 计算每张图片的 frame 转换为窗口的 frame (相对坐标系为 : window)
        UIImageView *imageView = [self getImageViewForCollectionCell:cell];
        CGRect rect = [imageView.superview convertRect:imageView.frame toView:nil];
        NSValue *value = [NSValue valueWithCGRect:rect];
        [centerImageViewBeginFrames addObject:value];
        
        // 从缓存池中取复用的 UIImageView.
        UIImageView *animationImageView = [self dequeueReuseImageView];
        animationImageView.image = imageView.image;
        animationImageView.frame = rect;
        [fromViewController.view.window addSubview:animationImageView];
        [centerImageViews addObject:animationImageView];
    }
    NSDictionary *dict = @{
                           kCenterImageViews : centerImageViews,
                           kCenterImageViewBeginFrames : centerImageViewBeginFrames
                           };
    return dict;
}

// 根据点击的那个 cell 的目标位置计算出出临近可见 cell 的目标位置 (相对坐标系为 : window)
- (NSMutableArray *)calculateCenterImageViewEndFramesWithBeginFrames:(NSArray *)centerImageViewBeginFrames tapImageViewFrame:(CGRect)tapImageViewFrame {
    CGRect tapImageViewEndFrame = CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_WIDTH*2.0/3.0);
    NSMutableArray *centerImageViewEndFrames = [NSMutableArray arrayWithCapacity:centerImageViewBeginFrames.count];
    for (int i = 0; i<centerImageViewBeginFrames.count; i++) {
        NSValue *value = centerImageViewBeginFrames[i];
        CGRect rect = [value CGRectValue];
        CGRect targetRect = tapImageViewEndFrame;
        // 在点击 cell 的左侧
        if (rect.origin.x < tapImageViewFrame.origin.x) {
            CGFloat detla = tapImageViewFrame.origin.x - rect.origin.x;
            targetRect.origin.x = -(detla * SCREEN_WIDTH)/tapImageViewFrame.size.width;
        }
        // 就是当前点击的 cell
        else if (rect.origin.x == tapImageViewFrame.origin.x){
            // Do nothing...
        }
        // 在点击 cell 的右侧
        else{
            CGFloat detla = rect.origin.x - tapImageViewFrame.origin.x;
            targetRect.origin.x = (detla*SCREEN_WIDTH)/tapImageViewFrame.size.width;
        }
        NSValue *targetValue = [NSValue valueWithCGRect:targetRect];
        [centerImageViewEndFrames addObject:targetValue];
    }
    return centerImageViewEndFrames;
}

// 重置imageView 的image 并缓存imageView
- (void)enqueueImageView:(UIImageView *)imageView {
    if (imageView.superview) {
        imageView.image = nil;
        [imageView removeFromSuperview];
        [self.imageviewReusePool addObject:imageView];
    }
}

// 从缓存池中读取一个imageView
- (UIImageView *)dequeueReuseImageView{
    UIImageView *resultImageView = nil;
    if (!self.imageviewReusePool) {
        self.imageviewReusePool = [NSMutableArray array];
    }
    if (self.imageviewReusePool.count) {
        resultImageView = self.imageviewReusePool.firstObject;
        [self.imageviewReusePool removeObject:resultImageView];
    }else {
        resultImageView = [UIImageView new];
    }
    return  resultImageView;
}

// 获取collectionview cell 的imageview
-(UIImageView *)getImageViewForCollectionCell:(UICollectionViewCell *)cell{
    UIImageView *result = nil;
    UIView *collectionViewContentView = cell.subviews.firstObject;
    NSArray *views = collectionViewContentView.subviews;
    for (UIView *view in views) {
        if (view.tag == CLCollectionViewCellImageViewTag) {
            result = (UIImageView *)view;
            break;
        }
    }
    return result;
}

// 按需要切割出我们需要的图片
- (UIImage *)clipImage:(UIImage *)snapImage clipPointY:(CGFloat)pointY clipType:(CLClipImageType)clipType {
    // 按需要裁切图片
    CGSize imageSize = snapImage.size;
    if (pointY > 0 && pointY < imageSize.height) {
        CGFloat scale = [UIScreen mainScreen].scale;
        CGRect rect = CGRectNull;
        // 根据类型计算将要裁切的图片大小
        if (clipType == CLClipImageTypeUp) {
            rect = CGRectMake(0, 0, imageSize.width * scale, pointY *scale);
        }else if (clipType == CLClipImageTypeDown){
            rect = CGRectMake(0, pointY * scale, imageSize.width * scale, (imageSize.height - pointY) * scale);
        }else if (clipType == CLClipImageTypeCenter) {
            rect = CGRectMake(0, pointY * scale, imageSize.width * scale, 0);
        }
        CGImageRef sourceImageRef = [snapImage CGImage];
        CGImageRef newImageRef = CGImageCreateWithImageInRect(sourceImageRef, rect);
        UIImage *clippedImage = [UIImage imageWithCGImage:newImageRef];
        return clippedImage;
    }
    return nil;
}
@end
